package com.canoo.cog.ui.welcome; /* * #%L * code-of-gotham * %% * Copyright (C) 2015 Canoo Engineering AG * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.util.ArrayList; import java.util.List; import com.canoo.cog.solver.CityNode; import com.canoo.cog.solver.LittleBetterSolverEver; import com.canoo.cog.solver.OptimumSolver; import com.canoo.cog.solver.SimplestSolverEver; import com.canoo.cog.solver.Solver; import com.canoo.cog.solver.SolverMaximusHaeckius; import com.canoo.cog.solver.SonarToStrategyConerter; import com.canoo.cog.sonar.SonarException; import com.canoo.cog.sonar.SonarService; import com.canoo.cog.sonar.model.CityModel; import com.canoo.cog.sonar.model.SonarProject; import com.canoo.cog.ui.city.CityStage; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.ProgressIndicator; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.input.KeyCode; class WelcomeController { // Property Keys private static final String COG_PROXY_KEY = "cogProxy"; private static final String COG_SONAR_HOST_KEY = "cogSonarHost"; // Alert Messages public static final String PROXY_FORM_ERROR_HEADER = "Proxy is not well formed."; public static final String PROXY_FORM_ERROR_CONTENT = "The proxy %s does not have the appropriate format {hostname}:{port}."; public static final String PROJECT_LIST_EMPTY_HEAER = "Project list is empty."; public static final String PROJECT_LIST_EMPTY_CONTENT = "The project list retrieved from %s does not return any projects."; public static final String PROJECTS_LOAD_ERROR_HEADER = "Could not load Projects."; public static final String PROJECTS_LOAD_ERROR_CONTENT = "An error occurred when communicating with %s. The server does not seem to be reachable."; public static final String CITY_BUILD_ERROR_HEADER = "The city could not be built."; public static final String CITY_BUILD_ERROR_CONTENT = "An Exception occurred when getting the city information from the sonar server %s"; @FXML private TextField sonarHostname; @FXML private TextField proxy; @FXML private PasswordField passwordTextField; @FXML private TextField usernameField; @FXML private Button loadButton; @FXML private ComboBox<Solver> solverBox; @FXML private CheckBox musicCheck; @FXML private Button startButton; @FXML private TableView projectTable; @FXML private TableColumn<SonarProject, String> keyColumn; @FXML private TableColumn<SonarProject, String> nameColumn; @FXML private TableColumn<SonarProject, String> versionColumn; @FXML private ProgressIndicator progressIndicator; @FXML private Label progressText; private SonarService sonarService; private List<SonarProject> projects; private boolean isCityLoading; private BooleanBinding isDataOrCityLoading; WelcomeController(SonarService sonarService) { this.sonarService = sonarService; } public void init() { // Set server values setConfiguredServerValues(); //Initialize Is Loading Property isCityLoading = false; isDataOrCityLoading = new BooleanBinding() { @Override protected boolean computeValue() { return isCityLoading; } }; // Bind progress indicator progressIndicator.visibleProperty().bind(isDataOrCityLoading); progressText.visibleProperty().bind(isDataOrCityLoading); // Enter event that triggers project load addLoadProjectsOnEnterEvent(sonarHostname); addLoadProjectsOnEnterEvent(proxy); addLoadProjectsOnEnterEvent(usernameField); addLoadProjectsOnEnterEvent(passwordTextField); // Bind disable property to is city loading projectTable.disableProperty().bind(isDataOrCityLoading); sonarHostname.disableProperty().bind(isDataOrCityLoading); proxy.disableProperty().bind(isDataOrCityLoading); usernameField.disableProperty().bind(isDataOrCityLoading); passwordTextField.disableProperty().bind(isDataOrCityLoading); solverBox.disableProperty().bind(isDataOrCityLoading); musicCheck.disableProperty().bind(isDataOrCityLoading); // Initialize the projects table keyColumn.setCellValueFactory(new PropertyValueFactory<SonarProject, String>("key")); nameColumn.setCellValueFactory(new PropertyValueFactory<SonarProject, String>("name")); versionColumn.setCellValueFactory(new PropertyValueFactory<SonarProject, String>("version")); projectTable.setRowFactory(tv -> { TableRow<String> row = new TableRow<>(); row.setOnMouseClicked(event -> { if (event.getClickCount() == 2 && (!row.isEmpty())) { loadCodeCity(); } }); return row; }); // Fill ComboBox with Solver possibilities final ArrayList<Solver> solvers = new ArrayList<>(); solvers.add(new SolverMaximusHaeckius()); solvers.add(new OptimumSolver()); solvers.add(new LittleBetterSolverEver()); solvers.add(new SimplestSolverEver()); solverBox.getItems().addAll(solvers); solverBox.getSelectionModel().select(0); // Initialize the buttons loadButton.setOnMouseClicked(event -> loadProjects()); loadButton.disableProperty().bind(Bindings.or(sonarHostname.textProperty().isEmpty(), isDataOrCityLoading)); startButton.setOnMouseClicked(event -> loadCodeCity()); startButton.disableProperty().bind(Bindings.or(isDataOrCityLoading, projectTable.getSelectionModel().selectedIndexProperty().lessThan(0))); Platform.runLater(projectTable::requestFocus); } private void addLoadProjectsOnEnterEvent(TextField sonarHostname) { sonarHostname.setOnKeyPressed(event -> { if (event.getCode() == KeyCode.ENTER) { loadProjects(); } }); } private void setConfiguredServerValues() { // Sonar String sonarHostnameDefault = System.getProperty(COG_SONAR_HOST_KEY); if (sonarHostnameDefault != null && !sonarHostnameDefault.isEmpty()) { sonarHostname.setText(sonarHostnameDefault); } // Proxy String proxyDefault = System.getProperty(COG_PROXY_KEY); if (proxyDefault != null && !proxyDefault.isEmpty()) { proxy.setText(proxyDefault); } } private void loadProjects() { // Load Projects in separate UI thread new Thread(() -> { setIsDataOrCityLoading(true); try { sonarService.setSonarSettings(sonarHostname.getText(), usernameField.getText(), passwordTextField.getText(), proxy.getText()); try { projects = sonarService.getProjects(); if (projects.isEmpty()) { showAlert(AlertType.WARNING, PROJECT_LIST_EMPTY_HEAER, String.format(PROJECT_LIST_EMPTY_CONTENT, sonarHostname.getText())); } Platform.runLater(() -> projectTable.setItems(FXCollections.observableArrayList(projects))); } catch (SonarException e) { showAlert(AlertType.ERROR, PROJECTS_LOAD_ERROR_HEADER, String.format(PROJECTS_LOAD_ERROR_CONTENT, sonarHostname.getText())); } } catch (SonarException e) { showAlert(AlertType.ERROR, PROXY_FORM_ERROR_HEADER, String.format(PROXY_FORM_ERROR_CONTENT, proxy.getText())); setIsDataOrCityLoading(false); } setIsDataOrCityLoading(false); }).start(); } private void loadCodeCity() { // Load Projects in separate UI thread new Thread(() -> { try { // Disable Welcome Scren while City is loaded setIsDataOrCityLoading(true); // Get City Data from Sonar SonarProject selectedItem = (SonarProject) projectTable.getSelectionModel().getSelectedItem(); CityModel cityData = sonarService.getCityData(selectedItem.getKey()); // Solve problem with Solver final int STREET_SIZE = 6; Solver solver = solverBox.getSelectionModel().getSelectedItem(); CityNode resultNode = new SonarToStrategyConerter().convertCityToNode(cityData); solver.solveProblem(resultNode, STREET_SIZE); // Start City Application final CityStage cityStage = new CityStage(cityData, resultNode, musicCheck.isSelected()); Platform.runLater(cityStage::startStage); // Enable Welcome Screen again after loading City setIsDataOrCityLoading(false); } catch (SonarException e) { showAlert(AlertType.ERROR, CITY_BUILD_ERROR_HEADER, String.format(CITY_BUILD_ERROR_CONTENT, sonarHostname)); } }).start(); } private void setIsDataOrCityLoading(boolean isCityLoading) { this.isCityLoading = isCityLoading; isDataOrCityLoading.invalidate(); } private void showAlert(final AlertType alertType, final String header, final String content) { Platform.runLater(() -> { Alert alert = new Alert(alertType); alert.setTitle(alertType.toString() + ": Code Of Gotham"); alert.setHeaderText(header); alert.setContentText(content); alert.showAndWait(); }); } }